/********************************************************************
文件名称:   UsbCdcCan.c

文件功能:   该程序为单片机usbd cdc接口程序

文件说明:   该程序为单片机usbd cdc接口程序，从keil virual com程序下
            移植，程序思路大致都是实现回调函数。

当前版本:   V1.0

修改记录:   2016-10-27 16:20:34   王  明  创建
********************************************************************/
#include <stdbool.h>
#include "rl_usb.h"
#include "RTE_Components.h"
#include "Driver_CAN.h"
#include "stdio.h"
#include "string.h"
#include "rngLib.h"

//#pragma pack(1)

#define DEBUG                   0
#define LOW_LEVL_DEBUG          0
#define CAN_MSG_DATA_LENGTH     8       // 标准帧和扩展帧均为8个字节
#define CAN_MSG_FIFO_SIZE       100     // 单片机can接收FIFO大小
// CAN Driver Controller selector
#define  CAN_CONTROLLER         1       // CAN Controller number

#define _CAN_Driver_(n)         Driver_CAN##n
#define  CAN_Driver_(n)          _CAN_Driver_(n)
extern   ARM_DRIVER_CAN         CAN_Driver_(CAN_CONTROLLER);
#define  ptrCAN                 (&CAN_Driver_(CAN_CONTROLLER))

uint32_t                        rx_rtr_tx_data_obj_idx = 0xFFFFFFFFU;
uint32_t                        rx_rtr_obj_idx         = 0xFFFFFFFFU;
ARM_CAN_MSG_INFO                rx_rtr_msg_info;
uint32_t                        tx_data_obj_idx        = 0xFFFFFFFFU;
uint8_t                         rx_data[8];
ARM_CAN_MSG_INFO                tx_data_msg_info;

RING_ID                         g_CanRecvRingId = NULL;

osThreadId                      tid_CanToUsb;

osSemaphoreId                   g_SemaphoreCanToUsb;      // Semaphore ID
osSemaphoreDef                  (g_SemaphoreCanToUsb);    // Semaphore definition


typedef struct CanMsg_s
{
    ARM_CAN_MSG_INFO msgInfo;
    uint8_t data[CAN_MSG_DATA_LENGTH];
} CanMsg_t;

/* 函数声明 */
void CAN_SignalUnitEvent (uint32_t event);
void CAN_SignalObjectEvent (uint32_t obj_idx, uint32_t event);

/********************************************************************
函数名称:   Can1Init

函数功能:   第一路can初始化程序

参数名称        类型            输入/输出           含义

返回值  :   成功：0 失败：错误码

函数说明:   第一路can初始化程序，注意stm32的滤波器的设置，目前设置为
            接收所有can帧。

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
int Can1Init(void)
{
    ARM_CAN_CAPABILITIES     can_cap;
    ARM_CAN_OBJ_CAPABILITIES can_obj_cap;
    int32_t                  status;
    uint32_t                 i, num_objects, clock;

    can_cap = ptrCAN->GetCapabilities (); // Get CAN driver capabilities
    num_objects = can_cap.num_objects;    // Number of receive/transmit objects

    status = ptrCAN->Initialize    (CAN_SignalUnitEvent, CAN_SignalObjectEvent);  // Initialize CAN driver
    if (status != ARM_DRIVER_OK )
    {
        return -1;
    }

    status = ptrCAN->PowerControl  (ARM_POWER_FULL);                              // Power-up CAN controller
    if (status != ARM_DRIVER_OK )
    {
        return -2;
    }

    status = ptrCAN->SetMode       (ARM_CAN_MODE_INITIALIZATION);                 // Activate initialization mode
    if (status != ARM_DRIVER_OK )
    {
        return -3;
    }

    clock = ptrCAN->GetClock();                                                   // Get CAN bas clock
    if ((clock % (8U * 125000U)) == 0U)                                           // If CAN base clock is divisible by 8 * 125000 without remainder
    {
        status = ptrCAN->SetBitrate    (ARM_CAN_BITRATE_NOMINAL,                    // Set nominal bitrate
                                        125000U,                                    // Set bitrate to 125 kbit/s
                                        ARM_CAN_BIT_PROP_SEG(5U)   |                // Set propagation segment to 5 time quanta
                                        ARM_CAN_BIT_PHASE_SEG1(1U) |                // Set phase segment 1 to 1 time quantum (sample point at 87.5% of bit time)
                                        ARM_CAN_BIT_PHASE_SEG2(1U) |                // Set phase segment 2 to 1 time quantum (total bit is 8 time quanta long)
                                        ARM_CAN_BIT_SJW(1U));                       // Resynchronization jump width is same as phase segment 2
    }
    else if ((clock % (10U * 125000U)) == 0U)                                     // If CAN base clock is divisible by 10 * 125000 without remainder
    {
        status = ptrCAN->SetBitrate    (ARM_CAN_BITRATE_NOMINAL,                    // Set nominal bitrate
                                        125000U,                                    // Set bitrate to 125 kbit/s
                                        ARM_CAN_BIT_PROP_SEG(7U)   |                // Set propagation segment to 7 time quanta
                                        ARM_CAN_BIT_PHASE_SEG1(1U) |                // Set phase segment 1 to 1 time quantum (sample point at 90% of bit time)
                                        ARM_CAN_BIT_PHASE_SEG2(1U) |                // Set phase segment 2 to 1 time quantum (total bit is 10 time quanta long)
                                        ARM_CAN_BIT_SJW(1U));                       // Resynchronization jump width is same as phase segment 2
    }
    else if ((clock % (12U * 125000U)) == 0U)                                     // If CAN base clock is divisible by 12 * 125000 without remainder
    {
        status = ptrCAN->SetBitrate    (ARM_CAN_BITRATE_NOMINAL,                    // Set nominal bitrate
                                        125000U,                                    // Set bitrate to 125 kbit/s
                                        ARM_CAN_BIT_PROP_SEG(7U)   |                // Set propagation segment to 7 time quanta
                                        ARM_CAN_BIT_PHASE_SEG1(2U) |                // Set phase segment 1 to 2 time quantum (sample point at 83.3% of bit time)
                                        ARM_CAN_BIT_PHASE_SEG2(2U) |                // Set phase segment 2 to 2 time quantum (total bit is 12 time quanta long)
                                        ARM_CAN_BIT_SJW(2U));                       // Resynchronization jump width is same as phase segment 2
    }
    else
    {
        return -4;
    }
    if (status != ARM_DRIVER_OK )
    {
        return -5;
    }

    for (i = 0U; i < num_objects; i++)                                            // Find first available object for receive and transmit
    {
        can_obj_cap = ptrCAN->ObjectGetCapabilities (i);                            // Get object capabilities

#if LOW_LEVL_DEBUG
        printf("**********************num_objects=%d***********************\n\r", i);
        printf("can_obj_cap.multiple_filters = %d\n\r", can_obj_cap.multiple_filters);
        printf("can_obj_cap.exact_filtering = %d\n\r", can_obj_cap.exact_filtering);
        printf("can_obj_cap.range_filtering = %d\n\r", can_obj_cap.range_filtering);
        printf("can_obj_cap.mask_filtering = %d\n\r", can_obj_cap.mask_filtering);
        printf("************************************************************\n\r");
#endif

        if      ((rx_rtr_tx_data_obj_idx == 0xFFFFFFFFU) && (can_obj_cap.rx_rtr_tx_data == 1U))
        {
            rx_rtr_tx_data_obj_idx = i;
            break;
        }
        else if ((rx_rtr_obj_idx         == 0xFFFFFFFFU) && (can_obj_cap.rx             == 1U))
        {
            rx_rtr_obj_idx         = i;
        }
        else if ((tx_data_obj_idx        == 0xFFFFFFFFU) && (can_obj_cap.tx             == 1U))
        {
            tx_data_obj_idx        = i;
            break;
        }
    }
    if ((rx_rtr_tx_data_obj_idx == 0xFFFFFFFFU) && ((rx_rtr_obj_idx == 0xFFFFFFFFU) || (tx_data_obj_idx == 0xFFFFFFFFU)))
    {
        return -6;
    }

    if (rx_rtr_tx_data_obj_idx != 0xFFFFFFFFU)                                    // If rx RTR tx data object is available
    {
        status = ptrCAN->ObjectSetFilter(rx_rtr_tx_data_obj_idx, ARM_CAN_FILTER_ID_MASKABLE_ADD, ARM_CAN_EXTENDED_ID(0x11223344), 0x0);
        if (status != ARM_DRIVER_OK )
        {
            return -7;
        }

        status = ptrCAN->ObjectSetFilter(rx_rtr_tx_data_obj_idx, ARM_CAN_FILTER_ID_MASKABLE_ADD, ARM_CAN_STANDARD_ID(0x11223344), 0x0);
        if (status != ARM_DRIVER_OK )
        {
            return -7;
        }


        // Configure rx RTR tx data object
        status = ptrCAN->ObjectConfigure(rx_rtr_tx_data_obj_idx, ARM_CAN_OBJ_RX_RTR_TX_DATA);
        if (status != ARM_DRIVER_OK )
        {
            return -8;
        }
    }
    else
    {
        // /* Set filter to receive messages with extended ID 0x11223344 */
        status = ptrCAN->ObjectSetFilter(rx_rtr_obj_idx, ARM_CAN_FILTER_ID_MASKABLE_ADD, ARM_CAN_EXTENDED_ID(0x11223344), 0x0);
        if (status != ARM_DRIVER_OK )
        {
            return -9;
        }

        // /* Set filter to receive messages with extended ID 0x11223344 */
        status = ptrCAN->ObjectSetFilter(rx_rtr_obj_idx, ARM_CAN_FILTER_ID_MASKABLE_ADD, ARM_CAN_STANDARD_ID(0x11223344), 0x0);
        if (status != ARM_DRIVER_OK )
        {
            return -9;
        }

        status = ptrCAN->ObjectConfigure(tx_data_obj_idx, ARM_CAN_OBJ_TX);          // Configure standard transmit object
        if (status != ARM_DRIVER_OK )
        {
            return -10;
        }

        status = ptrCAN->ObjectConfigure(rx_rtr_obj_idx,  ARM_CAN_OBJ_RX);          // Configure standard receive object
        if (status != ARM_DRIVER_OK )
        {
            return -11;
        }
    }

    status = ptrCAN->SetMode (ARM_CAN_MODE_NORMAL);                               // Activate normal operation mode
    if (status != ARM_DRIVER_OK )
    {
        return -12;
    }

    return 0;
}

/********************************************************************
函数名称:   ThreadCanToUsb

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void ThreadCanToUsb(void const *argument)
{
    int cnt = 0;
    int ret = 0;
    CanMsg_t CanMsg;

    for(;;)
    {
        osSemaphoreWait(g_SemaphoreCanToUsb, osWaitForever);

        /* 如果FIFO不为空则把数据发送 */
        while(TRUE != rngIsEmpty(g_CanRecvRingId))
        {
            /* 从缓存中取数据 */
            ret = rngBufGet(g_CanRecvRingId, (char *)&CanMsg, sizeof(CanMsg_t));
            if(ret > 0)
            {
                cnt = USBD_CDC_ACM_WriteData(0U, (const uint8_t *)&CanMsg, ret);
#if DEBUG
                printf("usb send = %d\n\r", cnt);
#endif
            }
        }
    }
}
osThreadDef (ThreadCanToUsb, osPriorityHigh, 1, 0);

/********************************************************************
函数名称:   CAN_SignalUnitEvent

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void CAN_SignalUnitEvent (uint32_t event)
{
    switch (event)
    {
    case ARM_CAN_EVENT_UNIT_ACTIVE:
        break;
    case ARM_CAN_EVENT_UNIT_WARNING:
        break;
    case ARM_CAN_EVENT_UNIT_PASSIVE:
        break;
    case ARM_CAN_EVENT_UNIT_BUS_OFF:
        break;
    }
}

/********************************************************************
函数名称:   CAN_SignalObjectEvent

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void CAN_SignalObjectEvent (uint32_t obj_idx, uint32_t event)
{
    int size = 0;
    int i = 0;
    CanMsg_t CanMsg;
    int send = 0;

    memset(&CanMsg, 0, sizeof(CanMsg_t));

    if (event == ARM_CAN_EVENT_RECEIVE)           // If receive event
    {
        if (obj_idx == rx_rtr_obj_idx)              // If receive object event
        {
            if ((size = ptrCAN->MessageRead(rx_rtr_obj_idx, &rx_rtr_msg_info, rx_data, 8U)) >= 0U)
            {
#if DEBUG
                /* 扩展帧 */
                if((rx_rtr_msg_info.id & 0x80000000) == 0x80000000)
                {
                    printf("Extend frame ID:%#x\n\r", (rx_rtr_msg_info.id & 0x1fffffff));
                }
                else /* 标准帧 */
                {
                    printf("Stander frame ID:%#x \n\r", rx_rtr_msg_info.id);
                }
                printf("rx_rtr_msg_info.rtr %d \n\r", rx_rtr_msg_info.rtr );
                printf("rx_rtr_msg_info.edl %d \n\r", rx_rtr_msg_info.edl );
                printf("rx_rtr_msg_info.brs %d \n\r", rx_rtr_msg_info.brs );
                printf("rx_rtr_msg_info.esi %d \n\r", rx_rtr_msg_info.esi );
                printf("rx_rtr_msg_info.dlc %d \n\r", rx_rtr_msg_info.dlc );

                for(i = 0; i < size; i++)
                {
                    printf("%#x ", rx_data[i]);
                }
                printf("\n\r");

                //memset(&tx_data_msg_info, 0U, sizeof(ARM_CAN_MSG_INFO));                      // Clear data message info structure
                //tx_data_msg_info.id = ARM_CAN_EXTENDED_ID(0x11223344U);                       // Set extended ID for transmit data message
                //ptrCAN->MessageSend(tx_data_obj_idx, &tx_data_msg_info, rx_data, size);
#endif

                /* 将can接收到的数据拷贝到CanMsg中，使用rngLib中的宏，其实为memcopy */
                bcopy(&rx_rtr_msg_info, &(CanMsg.msgInfo), sizeof(ARM_CAN_MSG_INFO));
                bcopy(&rx_data, &CanMsg.data, CAN_MSG_DATA_LENGTH);
#if DEBUG

                if((CanMsg.msgInfo.id & 0x80000000) == 0x80000000)
                {
                    printf("Extend frame ID:%#x\n\r", (CanMsg.msgInfo.id & 0x1fffffff));
                }
                else /* 标准帧 */
                {
                    printf("Stander frame ID:%#x \n\r", CanMsg.msgInfo.id);
                }
                printf("CanMsg.msgInfo.rtr %d \n\r", CanMsg.msgInfo.rtr );
                printf("CanMsg.msgInfo.edl %d \n\r", CanMsg.msgInfo.edl );
                printf("CanMsg.msgInfo.brs %d \n\r", CanMsg.msgInfo.brs );
                printf("CanMsg.msgInfo.esi %d \n\r", CanMsg.msgInfo.esi );
                printf("CanMsg.msgInfo.dlc %d \n\r", CanMsg.msgInfo.dlc );

                for(i = 0; i < CAN_MSG_DATA_LENGTH; i++)
                {
                    printf("%#x ", CanMsg.data[i]);
                }
                printf("\n\r");
#endif
                /* todo将数据保存到rngbuffer中，保存data和info */
                rngBufPut(g_CanRecvRingId, (char *)&CanMsg, sizeof(CanMsg_t));

                osSemaphoreRelease (g_SemaphoreCanToUsb);
#if 0
                //send = USBD_CDC_ACM_WriteData(0U, (const uint8_t *)&CanMsg, sizeof(CanMsg_t));

                //printf("send = %d\n\r", send);
#endif
            }
        }
    }
    if (event == ARM_CAN_EVENT_SEND_COMPLETE)     // If send completed event
    {
#if LOW_LEVL_DEBUG
        printf("ARM_CAN_EVENT_SEND_COMPLETE\n\r");
#endif
    }
}

/********************************************************************
函数名称:   USBD_CDCn_ACM_DataSent

函数功能:   The function USBD_CDCn_ACM_DataSent notifies that all data was sent.

参数名称        类型            输入/输出           含义
nbytes          size_t          input               number of bytes in ring buffer

返回值  :   无

函数说明:   Callback when all data was sent on Bulk IN Endpoint.
            目前测试发现该函数不起作用。数据发送完成后回调不会执行。

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void USBD_CDCn_ACM_DataSent (void)
{
#if 0
    int cnt = 0;
    int ret = 0;

    CanMsg_t CanMsg;

    /* 如果FIFO不为空则把数据发送 */
    if(TRUE != rngIsEmpty(g_CanRecvRingId))
    {
        printf("USBD_CDCn_ACM_DataSent TRUE != rngIsEmpty!\nn");

        /* 从缓存中取数据 */
        ret = rngBufGet(g_CanRecvRingId, (char *)&CanMsg, sizeof(CanMsg_t));
        if(ret > 0)
        {
            cnt = USBD_CDC_ACM_WriteData(0U, (const uint8_t *)&CanMsg, ret);
        }
    }
    else
    {
        return;
    }
#endif
}

/********************************************************************
函数名称:   USBD_CDC0_ACM_DataReceived

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void USBD_CDC0_ACM_DataReceived (uint32_t len)
{
    printf("USBD_CDC0_ACM_DataReceived\n\r");
}

/********************************************************************
函数名称:   USBD_CDC0_ACM_Initialize

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void USBD_CDC0_ACM_Initialize (void)
{
    int ret = 0;

#if LOW_LEVL_DEBUG
    printf("USBD_CDC0_ACM_Initialize was call!\n\r");
#endif
    ret = Can1Init();
    if(ret < 0)
    {
        printf("Can1Init faild!\n\r");
    }
    else
    {
#if LOW_LEVL_DEBUG
        printf("Can1Init succeed!\n\r");
#endif
    }

    /* 创建单片机can接收缓存 */
    g_CanRecvRingId = rngCreate(sizeof(CanMsg_t) * CAN_MSG_FIFO_SIZE);
    if(g_CanRecvRingId == NULL)
    {
#if DEBUG
        printf("g_CanRecvRingId rngCreate fiald!\n\r");
#endif
    }

    /* 创建can > usb任务 */
    g_SemaphoreCanToUsb = osSemaphoreCreate(osSemaphore(g_SemaphoreCanToUsb), 1);

    /* 创建can > usb信号量 */
    tid_CanToUsb = osThreadCreate(osThread(ThreadCanToUsb), NULL);
}

/********************************************************************
函数名称:   USBD_CDC0_ACM_Uninitialize

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void USBD_CDC0_ACM_Uninitialize (void)
{

}

/********************************************************************
函数名称:   USBD_CDC0_ACM_Reset

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void USBD_CDC0_ACM_Reset (void)
{

}

/********************************************************************
函数名称:   USBD_CDC0_ACM_SetLineCoding

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
bool USBD_CDC0_ACM_SetLineCoding (CDC_LINE_CODING *line_coding)
{
    return true;
}

/********************************************************************
函数名称:   USBD_CDC0_ACM_GetLineCoding

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:
修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
bool USBD_CDC0_ACM_GetLineCoding (CDC_LINE_CODING *line_coding)
{
    return true;
}

/********************************************************************
函数名称:   USBD_CDC0_ACM_SetControlLineState

函数功能:

参数名称        类型            输入/输出           含义

返回值  :

函数说明:

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
bool USBD_CDC0_ACM_SetControlLineState (uint16_t state)
{
    return true;
}
